PostgreSQL “IF” erro de sintaxe
-
03-07-2019 - |
Pergunta
Eu sou novo com o PostgreSQL, e eu já tenho o meu primeiro problema ..
Eu escrevi algum código para entender como funcionam transações, seguindo a etapa manual a passo.
Para ser breve, eu criei 2 tabelas, usuários e movimentos: no primeiro, há o nome, e-mail e de crédito colunas, nas segundas as colunas, para, importação
.Então, eu estava tentando desta forma:
BEGIN;
INSERT INTO movements (from, to, import) VALUES ('mary', 'steve', 600);
UPDATE users SET credit = credit - 600 WHERE name = 'mary';
UPDATE users SET credit = credit + 600 WHERE name = 'steve';
--here comes the problem!
IF (SELECT credit FROM users WHERE name = 'mary') < 0 THEN
ROLLBACK;
END IF
COMMIT;
Eu sempre recebo o erro:
ERRO: erro de sintaxe ou perto "IF"
Onde estou enganado?
P.S .: Não se concentrar no exemplo funcionalidade, é apenas um teste para mim entender as transações .. e agora, a cláusula if ...
Solução
Como Johannes já diz: você está misturando SQL regular com PL / pgSQL, a linguagem de procedimentos armazenados. O link que Johannes fornece devem explicar o conceito de procedimentos armazenados para você.
Acho que você está fazendo isso como um script? Executando uma declaração após o outro? Eu tenho medo que você só pode fazer o que você quer fazer dentro de um procedimento armazenado ou função, como você pode chamá-lo. Isto porque, quando você está executando instruções desta forma, cada declaração está em seu próprio sem relação ou informações sobre as outras declarações.
Além disso, você pode olhar para o seguinte link para obter mais informações sobre como usar o IF ... THEN ... ELSE ... END IF; condicionais dentro plpgsql:. ?? ligação
EDIT:
Eu não sei se ROLLBACK é permitido naquele ponto (porque cada procedimento armazenado já está em sua própria transação), mas você deve ser capaz de descobrir isso por si mesmo usando a extensa documentação @ http://www.postgresql.org . Aqui está uma função de exemplo com o seu código nele, também demonstrando alguma outra sintaxe:
CREATE OR REPLACE FUNCTION public.test()
RETURNS integer AS
$$
DECLARE
tempvar integer;
BEGIN
tempvar := 1;
INSERT INTO movements (from, to, import) VALUES ('mary', 'steve', 600);
UPDATE users SET credit = credit - 600 WHERE name = 'mary';
UPDATE users SET credit = credit + 600 WHERE name = 'steve';
--here comes the problem!
IF (SELECT credit FROM users WHERE name = 'mary') < 0 THEN
ROLLBACK;
END IF;
RETURN tempvar;
END
$$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER;
No entanto, se você está realmente indo por este caminho, eu recomendo usar um gerenciador GUI DB. É mais fácil para aprender tudo isso.
Outras dicas
Você parece usar SQL
simples, mas a declaração IF
faz parte do PL/pgSQL
linguagem procedural que faz parte do PostgreSQL.
Você poderia tentar modificar a parte IF, de:
IF (SELECT credit FROM users WHERE name = 'mary') < 0 THEN
ROLLBACK;
END IF
para
SELECT SUM(credit) INTO v_credit FROM users WHERE name = 'mary';
IF (v_credit) < 0 THEN
ROLLBACK;
END IF
Assumindo v_credit é uma variável que você definiu anteriormente. IMHO, Postgre assume retornos de consulta selecionar mais de um resultado, mesmo que você está muito certo de que ele é único. Então eu acho que você poderia tentar atribuir o valor a uma variável primeira antemão.
Se você quiser evitar a se você poderia reescrever seu código como:
BEGIN;
INSERT INTO movements (from, to, import)
SELECT 'mary', 'steve', CASE credit < 600 WHEN TRUE THEN 0 ELSE 600 END;
UPDATE users SET credit = credit - CASE credit < 600 WHEN TRUE THEN 0 ELSE 600 END
WHERE name = 'mary';
UPDATE users u SET u.credit = u.credit + CASE v.credit < 600 WHEN TRUE THEN 0 ELSE 600 END
FROM users v
WHERE u.name = 'steve' and v.name = 'mary'
COMMIT;
Sim, esta é :) estúpido.
Semelhante ao SQL da Microsoft e T / SQL, você deve ser capaz de misturar SQL regular com PL / pgSQL se eles estão na sequência correcta. Aqui está um exemplo onde os assuntos de seqüência em um SQL / proc PL armazenados mista:
Você não pode envolver declarações condicionais dentro do cursor - você deve colocar o cursor dentro da instrução condicional. Se você fizer a seqüência o contrário, você obterá o mesmo erro que você tinha visto, 'ERRO: erro de sintaxe ou perto 'SE''
CREATE OR REPLACE FUNCTION getSubsystemFaultListCount(_bunoid integer, _subsystem text, _starttime timestamp without time zone, _stoptime timestamp without time zone)
RETURNS refcursor AS
$BODY$
DECLARE mycurs refcursor;
BEGIN
IF _subsystem = 'ALL' THEN
OPEN mycurs FOR
SELECT count(*), fs_fault.faultcode, fs_fault.downloadtime
FROM fs_fault
WHERE fs_fault.bunoid = _bunoid
AND fs_fault.statusid IN(2, 4)
AND fs_fault.downloadtime BETWEEN _starttime AND _stoptime
GROUP BY fs_fault.faultcode, fs_fault.downloadtime;
RETURN mycurs;
ELSE
OPEN mycurs FOR
SELECT count(*), fs_fault.faultcode, fs_fault.downloadtime
FROM fs_fault
WHERE fs_fault.bunoid = _bunoid
AND fs_fault.subsystemid
IN(SELECT id FROM fs_subsystem WHERE type = _subsystem)
AND fs_fault.statusid IN(2, 4)
AND fs_fault.downloadtime BETWEEN _starttime AND _stoptime
GROUP BY fs_fault.faultcode, fs_fault.downloadtime;
RETURN mycurs;
END IF;
END;
$BODY$
Eu sou um novato no PostgresSQL; esta função é apenas um exemplo.